package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"io"
	"log"
	"sgrpc/grpc/proto/hello"
	"strconv"
	"time"
)

// 定义客户端一元拦截器
func ClientUnaryLoggerInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {

	err := invoker(ctx, method, req, reply, cc, opts...)
	if err != nil {
		log.Println(err)
		return err
	}
	return nil
}

// 定义客户端流式拦截器
func ClientStreamLoggerInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {

	stream, err := streamer(ctx, desc, cc, method, opts...)
	if err != nil {
		log.Println(err)
		return stream, err
	}
	return stream, nil
}

func main() {

	// 注册一元拦截器
	clientUnaryLoggerInterceptor := grpc.WithUnaryInterceptor(ClientUnaryLoggerInterceptor)
	// 注册流式拦截器
	clientStreamLoggerInterceptor := grpc.WithStreamInterceptor(ClientStreamLoggerInterceptor)

	conn, err := grpc.Dial("127.0.0.1:8000", grpc.WithTransportCredentials(insecure.NewCredentials()), clientUnaryLoggerInterceptor, clientStreamLoggerInterceptor)
	if err != nil {
		log.Fatal(err)
	}

	helloServiceClient := hello.NewHelloServiceClient(conn)

	err = SayHello(helloServiceClient) // 一元
	//err = LotsOfReplies(helloServiceClient) // 服务端流
	//err = LotsOfGreetings(helloServiceClient) // 客户端流
	//err = BidiHello(helloServiceClient) // 双向流
	if err != nil {
		fmt.Println(err)
	}
}

// 一元

func SayHello(client hello.HelloServiceClient) error {
	request := &hello.HelloRequest{
		Name: "一元RPC",
		Age:  18,
	}

	// 10秒超时
	ctx, cancelFunc := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))
	defer cancelFunc()

	helloResponse, err := client.SayHello(ctx, request)
	if err != nil {
		return err
	}

	fmt.Println(helloResponse)

	return nil
}

// 服务端流 服务端一直在发，所以客户端可以一直接收

func LotsOfReplies(client hello.HelloServiceClient) error {

	// 3秒超时
	ctx, cancelFunc := context.WithDeadline(context.Background(), time.Now().Add(20*time.Second))
	defer cancelFunc()

	repliesClient, err := client.LotsOfReplies(ctx, &hello.HelloRequest{
		Name: "服务端流式RPC",
		Age:  18,
	})

	if err != nil {
		return err
	}

	defer repliesClient.CloseSend()

	for {
		helloResponse, err := repliesClient.Recv()

		if err == io.EOF {
			return nil
		}

		if err != nil {
			return err
		}

		fmt.Println(helloResponse)
	}

}

// 客户端流 客户端可以发送多次

func LotsOfGreetings(client hello.HelloServiceClient) error {

	// 10秒超时
	ctx, cancelFunc := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))
	defer cancelFunc()

	greetingsClient, err := client.LotsOfGreetings(ctx)
	if err != nil {
		return err
	}

	defer greetingsClient.CloseSend()

	for i := 0; i < 10; i++ {

		err := greetingsClient.Send(&hello.HelloRequest{
			Name: "客户端流：" + strconv.Itoa(i),
			Age:  18,
		})

		if err != nil {
			return err
		}

	}

	return nil
}

// 双向流

func BidiHello(client hello.HelloServiceClient) error {

	// 10秒超时
	ctx, cancelFunc := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))
	defer cancelFunc()

	bidiClient, err := client.BidiHello(ctx)
	if err != nil {
		return err
	}

	defer bidiClient.CloseSend()

	for i := 0; i < 10; i++ {

		err := bidiClient.Send(&hello.HelloRequest{
			Name: "双向流" + strconv.Itoa(i),
			Age:  18,
		})

		if err != nil {
			return err
		}

		helloResponse, err := bidiClient.Recv()

		if err == io.EOF {
			return nil
		}

		if err != nil {
			return err
		}

		fmt.Println(helloResponse)
	}

	return nil
}
